#if !defined(__HTTP_SESSION_H__)
#define __HTTP_SESSION_H__

#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/config.hpp>
#include <boost/url.hpp>
#include <boost/url/parse_query.hpp>


#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
#include <thread>


#include "HttpRequest.hpp"
#include "HttpResponse.hpp"
#include <map>

// namespace beast = boost::beast;   // from <boost/beast.hpp>
// namespace http = beast::http;     // from <boost/beast/http.hpp>

class HttpSession : public boost::enable_shared_from_this<HttpSession>
{
public:
    static std::string server_name;
    typedef std::function<void(const HttpRequest &, HttpResponse &)> RequestHandler;

private:
    boost::beast::tcp_stream stream;
    std::string const doc_root;

    std::map<std::string, RequestHandler> get_handlers;
    std::map<std::string, RequestHandler> post_handlers;
    boost::beast::flat_buffer buffer;

    HttpRequest request;

public:
    HttpSession(boost::asio::ip::tcp::socket &&socket,
                std::string const &doc_root,
                std::map<std::string, RequestHandler> &get_handlers,
                std::map<std::string, RequestHandler> &post_handlers);
    ~HttpSession();

    void start();

private:
    // Start the asynchronous operation
    void run();

    void do_read();

    void on_read(
        boost::beast::error_code ec,
        std::size_t bytes_transferred);

    void send_response(boost::beast::http::message_generator &&msg);

    void on_write(
        bool keep_alive,
        boost::beast::error_code ec,
        std::size_t bytes_transferred);

    void do_close();

    // Return a response for the given request.
    //
    // The concrete type of the response message (which depends on the
    // request), is type-erased in message_generator.
    boost::beast::http::message_generator
    handle_request();

    // HttpResponse
    // request_file();
};

#endif // __HTTP_SESSION_H__
